package by.ad;

import static com.google.common.base.Charsets.UTF_8;
import static by.ad.HttpUtils.USER_AGENT;
import static by.ad.HttpUtils.REFERER;
import static by.ad.HttpUtils.getCookieValue;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;

public abstract class GoogleAnalytics {

  public static String getRandomNumber() {
    return Integer.toString((int) (Math.random() * 0x7fffffff));
  }
  
  // The last octect of the IP address is removed to anonymize the user.
  private static String anonymizeIP(final String remoteAddress) {
    if (remoteAddress == null || remoteAddress.isEmpty())
      return "";
    
    // Capture the first three octects of the IP address and replace the forth
    // with 0, e.g. 124.455.3.123 becomes 124.455.3.0
    final String regex = "^([^.]+\\.[^.]+\\.[^.]+\\.).*";
    final Pattern getFirstBitOfIPAddress = Pattern.compile(regex);
    final Matcher m = getFirstBitOfIPAddress.matcher(remoteAddress);
    return m.matches() ? (m.group(1) + "0") : "";
  }

  // Generate a visitor id for this hit.
  // If there is a visitor id in the cookie, use that, otherwise
  // use the guid if we have one, otherwise use a random number.
  private static String getVisitorId(
    final String guid, final String account, final String userAgent, final String cookie)
      throws NoSuchAlgorithmException, UnsupportedEncodingException 
  {
    // If there is a value in the cookie, don't change it.
    if (cookie != null && !cookie.isEmpty()) {
      return cookie;
    }

    final String message = (guid != null && !guid.isEmpty()) 
      // Create the visitor id using the guid.
      ? guid + account
      // otherwise this is a new user, create a new random id.
      : userAgent + getRandomNumber() + UUID.randomUUID().toString();

    final MessageDigest m = MessageDigest.getInstance("MD5");
    m.update(message.getBytes(UTF_8.name()), 0, message.length());
    final byte[] sum = m.digest();
    final BigInteger messageAsNumber = new BigInteger(1, sum);
    final String md5String = String.format("%016x", messageAsNumber);

    return "0x" + md5String.substring(0, 16);
  }

  // inspired by ga.jsp
  public String googleAnalyticsGetImageUrl(final HttpServletRequest request,
    final String gaAccount)
      throws UnsupportedEncodingException, NoSuchAlgorithmException 
  {
    final String utmGifLocation = "http://www.google-analytics.com/__utm.gif";
    final String version = "4.4sj";
    final String COOKIE_NAME = "__utmmobile";
    
    final String guidHeader = 
      request.getHeader("X-DCMGUID") != null 
        ? request.getHeader("X-DCMGUID") 
        : (request.getHeader("X-UP-SUBNO") != null 
          ? request.getHeader("X-UP-SUBNO") 
          : (request.getHeader("X-JPHONE-UID") != null
            ? request.getHeader("X-JPHONE-UID")
            : request.getHeader("X-EM-UID")));
    
    final String userAgent = request.getHeader(USER_AGENT) != null ? request.getHeader(USER_AGENT) : "";
    final String visitorId = getVisitorId(guidHeader, gaAccount, userAgent, 
      getCookieValue(request.getCookies(), COOKIE_NAME));
    
    final String domainName = request.getServerName();
    final String referer = request.getHeader(REFERER);
    final String documentReferer = (referer == null || referer.isEmpty()) ? "-" : referer;
    final String query = request.getQueryString() != null ? ("?" + request.getQueryString()) : "";
    final String documentPath = request.getRequestURI() + query;

    final String utmUrl = utmGifLocation + "?" +
      "utmwv=" + version +
      "&utmn=" + getRandomNumber() +
      "&utmhn=" + URLEncoder.encode(domainName, UTF_8.name()) +
      "&utmr=" + URLEncoder.encode(documentReferer, UTF_8.name()) +
      "&utmp=" + URLEncoder.encode(documentPath, UTF_8.name()) +
      "&utmac=" + gaAccount +
      "&utmcc=__utma%3D999.999.999.999.999.1%3B" +
      "&utmvid=" + visitorId +
      "&utmip=" + anonymizeIP(request.getRemoteAddr());

    return utmUrl.replace("&", "&amp;");
  }
  
}
